package com.bluexmicro.ota2.ui.screen.yika

import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
import android.bluetooth.le.ScanResult
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bluexmicro.bluetooth.BluetoothCentral
import com.bluexmicro.bluetooth.model.ScanMode
import com.bluexmicro.bluetooth.model.WriteType
import com.bluexmicro.bluetooth.scan.ScannerImpl
import com.bluexmicro.bluetooth.toUInt8
import com.bluexmicro.ota.FirmwareHelper
import com.bluexmicro.ota.dfu.DfuProcess
import com.bluexmicro.ota.dfu.ExitAction
import com.bluexmicro.ota.dfu.FirmwareBean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.util.UUID
import kotlin.Exception

class YiKaCheckViewModel : ViewModel() {

    companion object {
        const val uuid_service = "0000ff00-0000-1000-8000-00805f9b34fb"
        const val uuid_chara = "0000ff02-0000-1000-8000-00805f9b34fb"
    }

    val permissions by lazy {
        val array = mutableListOf<String>()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            array.add(android.Manifest.permission.BLUETOOTH_CONNECT)
            array.add(android.Manifest.permission.BLUETOOTH_SCAN)
        }
        array.add(android.Manifest.permission.ACCESS_FINE_LOCATION)
        array.add(android.Manifest.permission.ACCESS_COARSE_LOCATION)
        array
    }

    val items = mutableStateOf<List<FirmwareBean>>(emptyList())

    val progress = mutableStateOf(0) //0~100


    val checking = mutableStateOf(false)

    val ver = mutableStateOf<Int?>(null)
    val type = mutableStateOf<Int?>(null)


    private var cacheZip: File? = null
    fun onFileSelected(context: Context, zip: File) = viewModelScope.launch(Dispatchers.IO) {
        type.value = null
        ver.value = null
        val array = zip.nameWithoutExtension.split("_")
        if (array.size >= 2) {
            try {
                type.value = array[array.size - 1].toInt()
                ver.value = array[array.size - 2].replace("V", "").toInt()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        try {
            items.value = FirmwareHelper.unzipToFirmwares(context, zip)
            cacheZip = zip
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private val checked = mutableListOf<String>()

    private var job: Job? = null
    fun check(context: Context, rssi: Int) {
        job?.takeIf { it.isActive }?.apply { cancel() }
        BluetoothCentral.scanForPeripherals()
        job = viewModelScope.launch {
            checking.value = true
            while (checking.value) {
                val target = withContext(Dispatchers.Default) {
                    val list = BluetoothCentral.fetchScanResults(0L)
                    list.find {
                        val manufacturerData =
                            it.scanRecord?.getManufacturerSpecificData(0x09B3) ?: ByteArray(0)
                        val fit = when {
                            manufacturerData.size >= 9 -> {
                                val mType = manufacturerData[7].toUInt8()
                                val mVer = manufacturerData[8].toUInt8()

                                val fileVer = ver.value ?: 0
                                mType == type.value && fileVer == mVer
                            }

                            else -> false
                        }
                        it.rssi >= rssi && fit && !checked.contains(it.device.address)
                    }
                } ?: continue

                val peripheral =
                    BluetoothCentral.retrievePeripherals(context, target.device.address) ?: continue

                try {
                    BluetoothCentral.connect(context, peripheral)
                    val services = peripheral.discoverServices().getOrNull()
                    val service = services?.find { it.uuid.equals(UUID.fromString(uuid_service)) }
                    val chara = service?.getCharacteristic(UUID.fromString(uuid_chara))
                        ?: throw IllegalStateException("连接失败")
                    peripheral.write(chara, WriteType.WithoutResponse, byteArrayOf(0x04))
                    if (!checked.contains(target.device.address)) {
                        checked.add(target.device.address)
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
                withContext(Dispatchers.Default) {
                    delay(300)
                }
                BluetoothCentral.releasePeripheral(peripheral)
                withContext(Dispatchers.Default) {
                    delay(1000)
                }
            }
        }
    }


    fun stop() {
        BluetoothCentral.stopScan()
        job?.takeIf { it.isActive }?.apply { cancel() }
        checking.value = false
    }


    override fun onCleared() {
        super.onCleared()
        stop()
    }

}